#ifndef ARBOL_H_
#define ARBOL_H_

#include "BloqueArbol.h"
#include "../../Constantes.h"
#include "../../claves/Key.h"
#include "../../claves/TipoClave.h"
#include "../Elemento.h"
#include "../../recursoDeAlmacenamiento/RecursoDeAlmacenamientoDirecto.h"
#include <list>

using namespace std;
class TestArbolEnArchivo;

class Arbol {

	/*Amigos para poder hacer pruebas internas*/
	friend class TestArbolEnArchivo;
private:

	string nombre;
	unsigned CANT_MAX_CLAVES;
	RecursoDeAlmacenamientoDirecto* recurso;
	RecursoDeAlmacenamientoDirecto* recursoRaiz;
	BloqueArbol* raiz;
	BloqueArbol* hojaActual;
	offset actual;
	list<BloqueArbol*> ultimosAccedidos;
	TipoClave* extractor;
	cantBytes tamanioBloque;
	bool inicializado;
	cantBytes tamanioRaiz;

	/* TODO Metodos de acceso a disco implementaciones que estan en la fabrica */
	BloqueArbol* traerBloqueArbol(offset nroComponente);

	void guardarModificado(BloqueArbol* bloque);

	void inicializarBloque(BloqueArbol* bloque);

	void ultimosAdisco();

	/*Si el Bloque buscado esta en la lista de ultimosAccedidos lo quita y lo retorna, sino lo trae
	 * de disco pero no lo ingresa en la lista.
	 * El que pide en bloque debe ocuparse de guardar el bloque si lo modifica y
	 * liberar la memoria del bloque.
	 */
	BloqueArbol* getLibre(offset o);

	void cambiarRaizPor(offset idNueva);

	void borrarRaiz();

	/*
	 * Pre: -
	 * Pos: carga la raiz. en caso de no existir en el disco la crea.
	 */
	void cargarRaiz();

	/*
	 * Pre: -
	 * Pos: Cuando el recurso nunca ha sido usado, crea la raiz y la guarda en disco
	 * inicialmente la raiz no tendra claves.
	 *
	 * Nota: No debe llamarse a esta funcion. La llama automaticamente "cargarRaiz"
	 */

	BloqueArbol* crearRaiz();
	cantBytes calcularTamanio(cantBytes orden, cantBytes tamanioMaxClave);
public:

	/* Pre: raiz distinta de nulo y correcta (tamanio doble que los demas bloques)
	 * Pos: Guarda el estado de la raiz en el disco.
	 */
	bool guardarRaiz();

	Arbol(string nombre, TipoClave* extractor, int orden,
			cantBytes tamanioMaxClave);

	virtual ~Arbol();

	bool estaVacio();

	unsigned getCantClavesMax();

	bool inicializar();

	/* Pre: el offset debe ser valido.
	 * Post: Busca el bloque en la lista de ultimosAccedidos, si no lo encuentra lo trae de disco y lo retorna.
	 */
	BloqueArbol* get(offset o);

	/* Pre:
	 * Post: Crea un bloque nuevo, lo guarda en la lista de ultimosAccedidos y lo retorna.
	 */
	BloqueArbol* getNew(char tipo);

	/*se setea la raiz del arbol*/
	void setRaiz(offset raiz);

	/*Setea la primer hoja como la actual*/
	void irInicio();

	/*Retorna un puntero al elemento actual, si se llega al final retorna NULL*/
	Elemento* proximo();

	bool tieneProximo();

	/* Se intenta insertar un elemento en la hoja correspondiente.
	 * Si la clave no estÃ¡ duplicada, se inserta. Sino, se retorna duplicado (y no se inserta)*/
	Resultado insertar(const Elemento& elementoAInsertar);

	/* Le paso la clave a buscar.
	 * En res devuelve el estado de la operacion.
	 * Retorna el elemento buscado o NULL si no existe.
	 */
	Elemento* buscar(const Key& clave, Resultado& res);

	/* Si existe el elemento, quita el elemento del arbol y retorna RES_OK.
	 * Si la clave no esta en el arbol, se retorna RES_INEXISTENTE*/
	Resultado borrar(Elemento& elemento);

	/*Si existe la clave, quita el elemento correspondiente del arbol y retorna RES_OK.
	 * Si la clave no esta en el arbol, se retorna RES_INEXISTENTE*/
	Resultado borrar(const Key& clave);

	/*se retorna la raiz del arbol*/
	BloqueArbol* getRaiz();

	/*se ve el arbol por panatalla, las claves de cada nodo*/
	void visualizar();
};

#endif /* ARBOL_H_ */
